/*
 * Copyright 2000 the original author or authors.
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * 
 *      http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include "WtCollectionCmds.h"
#include "WtUtil.h"
#include "WtBasicCmds.h"

/* Helper to manage collection objects. Implements the "object
   method args" command style. */

WtClnCmdStatus WtClnMethodHelper(ClientData clientData, Tcl_Interp *interp,
    int objc, Tcl_Obj *const objv[], int *tclRet, Tcl_Obj **clnPtr,
    Tcl_ObjType *type, int readOnly, int appendUsage)
{
  int ret = TCL_ERROR, status = WT_CLN_CMD_DONE, error = 0;
  int size, listLen;
  WtContext *w;
  const char *subCmd;
  Tcl_Obj *cln, *list, *item;

  w = (WtContext *)Tcl_GetAssocData(interp, "wt::context", NULL);

  if (objc < 2) {
    if (appendUsage) {
      WtClnMethodUsageError(interp, objv[0], readOnly);
    }
    return WT_CLN_CMD_MISSING;
  }

  subCmd = WtToString(objv[1]);
  cln = *clnPtr;

  if (!strcmp(subCmd, "count")) {

    /* count command */

    if (objc != 2) {
      Tcl_AppendResult(interp, wtBadUsagePrefix,
        WtToString(objv[0]), " ", WtToString(objv[1]));
    } else if (WtClnSize(cln, &size, interp)) {
      Tcl_SetObjResult(interp, Tcl_NewIntObj(size));
      ret = TCL_OK;
    }

  } else if (!strcmp(subCmd, "has")) {

    /* has command */

    if (objc != 3) {
      Tcl_AppendResult(interp, wtBadUsagePrefix,
        WtToString(objv[0]), " ", WtToString(objv[1]), " ",
        " name", NULL);
    } else if (WtFindClnItem(cln, objv[2], &item, interp)) {
      Tcl_SetObjResult(interp, Tcl_NewBooleanObj(item != NULL));
      ret = TCL_OK;
    }

  } else if (!strcmp(subCmd, "keys")) {

    /* keys command */

    if (objc != 2) {
      Tcl_AppendResult(interp, wtBadUsagePrefix,
        WtToString(objv[0]), " ", WtToString(objv[1]), NULL);
    } else if (WtGetClnKeys(cln, &list, interp)) {
      Tcl_SetObjResult(interp, list);
      ret = TCL_OK;
    }

  } else if (!strcmp(subCmd, "values")) {

    /* values command */

    if (objc != 2) {
      Tcl_AppendResult(interp, wtBadUsagePrefix,
        WtToString(objv[0]), " ", WtToString(objv[1]), NULL);
    } else if (WtGetClnValues(cln, &list, interp)) {
      Tcl_SetObjResult(interp, list);
      ret = TCL_OK;
    }

  } else if (!strcmp(subCmd, "get")) {

    /* get command */

    if (objc != 3 && objc != 4) {
      Tcl_AppendResult(interp, wtBadUsagePrefix,
        WtToString(objv[0]), " ",
        WtToString(objv[1]), " name ", "?defaultValue?",
        NULL);
    } else if (WtFindClnItem(cln, objv[2], &item, interp)) {
      if (item) {
        Tcl_SetObjResult(interp, item);
        ret = TCL_OK;
      } else if (objc > 3) {
        Tcl_SetObjResult(interp, objv[3]);
        ret = TCL_OK;
      } else {
        Tcl_AppendResult(interp, "No item with key \"",
          WtToString(objv[2]),
          "\" exists, and no default value was specified.",
          NULL);
      }
    }

  } else if (!strcmp(subCmd, "getAll")) {

    /* getAll command */

    if (objc != 3 || objc != 4) {
      Tcl_AppendResult(interp, "Incorrect usage. Should be:\n",
        WtToString(objv[0]), " ", WtToString(objv[1]), " ",
        "name ", "?defaultValue?", NULL);
    } else if (WtFindAllClnItems(cln, objv[2], &list, interp)) {
      if (Tcl_ListObjLength(interp, objv[2], &listLen) == TCL_OK) {
        if (listLen) {
          Tcl_SetObjResult(interp, list);
          ret = TCL_OK;
        } else if (objc > 3) {
          Tcl_SetObjResult(interp, objv[3]);
          ret = TCL_OK;
        } else {
          Tcl_AppendResult(interp, "No entry with key \"",
            WtToString(objv[2]),
            "\" exists, and no default value was specified.",
            NULL);
        }
      }
    }

  } else if (!strcmp(subCmd, "add") && !readOnly) {

    /* add command */

    if (objc != 3) {
      Tcl_AppendResult(interp, "incorrect usage: should be: \n",
        WtToString(objv[0]), " ", WtToString(objv[1]), " item",
        NULL);
    } else if (WtAppendClnItem(cln, objv[2], interp)) {
      Tcl_SetObjResult(interp, objv[2]);
      ret = TCL_OK;
    }

  } else if (!strcmp(subCmd, "addList") && !readOnly) {

    /* addList command */

    if (objc != 3) {
      Tcl_AppendResult(interp, wtBadUsagePrefix,
        WtToString(objv[0]), " ", WtToString(objv[1]), " list",
        NULL);
    } else if (Tcl_ListObjLength(interp, objv[2], &listLen) ==
        TCL_OK) {
      if (WtAppendClnItemList(cln, objv[2], interp)) {
        Tcl_SetObjResult(interp, WtGetClnItems(cln));
        ret = TCL_OK;
      }
    }

  } else if (!strcmp(subCmd, "remove") && !readOnly) {

    /* remove command */

    if (objc != 3) {
      Tcl_AppendResult(interp, wtBadUsagePrefix,
        WtToString(objv[0]), " ", WtToString(objv[1]),
        " name", NULL);
    } else if (WtRemoveFromClnByKey(cln, objv[2], -1, interp)) {
      ret = TCL_OK;
    }

  } else if (!strcmp(subCmd, "removeList") && !readOnly) {

    /* removeList command */

    if (objc != 3) {
      Tcl_AppendResult(interp, wtBadUsagePrefix,
        WtToString(objv[0]), " ", WtToString(objv[1]), " list",
        NULL);
    } else if (Tcl_ListObjLength(interp, objv[2], &listLen) ==
        TCL_OK) {
      if (WtRemoveFromClnByKeyList(cln, objv[2], -1, interp)) {
        ret = TCL_OK;
      }
    }

  } else if (!strcmp(subCmd, "clear") && !readOnly) {

    /* clear command */

    WtClearCollection(cln);
    ret = TCL_OK;

  } else if (!strcmp(subCmd, "list")) {

    /* list command */

    if (objc != 2) {
      Tcl_AppendResult(interp, wtBadUsagePrefix,
        WtToString(objv[0]), " ", WtToString(objv[1]), NULL);
    } else {
      Tcl_SetObjResult(interp, WtGetClnItems(cln));
      ret = TCL_OK;
    }

  } else if (!strcmp(subCmd, "array")) {

    /* array command */

    if (objc < 3) {
      Tcl_AppendResult(interp, wtBadUsagePrefix,
        WtToString(objv[0]), " ", WtToString(objv[1]), " ",
        "arrayName", NULL);
    } else if (WtClnToArray(interp, cln, objv[2], 1)) {
      ret = TCL_OK;
    }

  } else {

    /* unknown command */

    status = WT_CLN_CMD_NOT_FOUND;

    if (appendUsage) {
      WtClnMethodUsageError(interp, objv[0], readOnly);
    }

  }

  *tclRet = ret;

  return status;
}

void WtClnMethodUsageError(Tcl_Interp *interp, Tcl_Obj *cmd, int readOnly)
{
  Tcl_AppendResult(interp, wtBadUsagePrefix, "\n", NULL);
  WtClnMethodAppendUsage(interp, cmd, readOnly);
}

void WtClnMethodAppendUsage(Tcl_Interp *interp, Tcl_Obj *cmd, int readOnly)
{
  char *cmdStr = WtToString(cmd);

  if (readOnly) {
    Tcl_AppendResult(interp,
      cmdStr, " count\n",
      cmdStr, " has key\n",
      cmdStr, " keys\n",
      cmdStr, " values\n",
      cmdStr, " get key ?defaultValue?\n",
      cmdStr, " getAll key ?defaultValue?\n",
      cmdStr, " items\n",
      cmdStr, " list\n",
      cmdStr, " array arrayName\n",
      NULL);
  } else {
    Tcl_AppendResult(interp,
      cmdStr, " count\n",
      cmdStr, " has key\n",
      cmdStr, " keys\n",
      cmdStr, " values\n",
      cmdStr, " get key ?defaultValue?\n",
      cmdStr, " getAll key ?defaultValue?\n",
      cmdStr, " add item\n",
      cmdStr, " addList list\n",
      cmdStr, " remove key\n",
      cmdStr, " removeList list\n",
      cmdStr, " clear\n",
      cmdStr, " list\n",
      cmdStr, " array arrayName\n",
      NULL);
  }
}
